package api.storage;

import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamWriter;

import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;

import api.Person;

/**
 * @author Ann Raboschuk
 */
public class DataStorageXML implements IDataStorage
{
   private String filename;
   private List<Person> list;

   public DataStorageXML(String filename)
   {
      this.filename = filename;
   }

   @Override
   public List<Person> load() throws Exception
   {
      SAXParserFactory factory = SAXParserFactory.newInstance();
      SAXParser saxParser = factory.newSAXParser();
      list = new ArrayList<Person>();
      DefaultHandler handler = new DefaultHandler()
      {
         Person person = null;
         Field field = null;

         public void startElement(String uri, String localName, String qName,
               Attributes attributes) throws SAXException
         {
            if (!qName.equals("List"))
            {
               if (qName.equals("Person"))
                  person = new Person();
               else
               {
                  try
                  {
                     field = Class.forName("api.Person").getDeclaredField(qName);
                  }
                  catch (Exception ex)
                  {
                     System.err.println(ex);
                  }
               }
            }
         }

         public void characters(char ch[], int start, int length)
               throws SAXException
         {
            field.setAccessible(true);
            Class<?> fieldType = field.getType();
            String value = new String(ch, start, length);
            try
            {
               if (fieldType.equals(String.class))
                  field.set(person, fieldType.cast(value));
               else
               {
                  if (fieldType.equals(Character.class))
                     field.set(person, value.charAt(0));
                  else
                  {
                     Method method = fieldType.getMethod("valueOf", String.class);
                     field.set(person, method.invoke(null, value));
                  }
               }
            }
            catch (Exception ex)
            {
               ex.printStackTrace();
            }
         }

         public void endElement(String namespaceURI, String localName,
               String qName) throws SAXException
         {
            if (qName.equals("Person"))
               list.add(person);
         }
      };
      saxParser.parse(new File(filename), handler);
      return list;
   }

   @Override
   public void save(List<Person> records) throws Exception
   {
      XMLOutputFactory factory = XMLOutputFactory.newInstance();
      XMLStreamWriter writer = factory.createXMLStreamWriter(new FileWriter(
            filename));

      writer.writeStartElement("List");

      Iterator<Person> iterator = records.iterator();
      Person current = null;
      Field[] fields = Class.forName("api.Person").getDeclaredFields();
      while (iterator.hasNext())
      {
         writer.writeStartElement("Person");
         current = iterator.next();
         for (Field field : fields)
         {
            if (!Modifier.isStatic(field.getModifiers()))
            {
               field.setAccessible(true);
               writer.writeStartElement(field.getName());
               writer.writeCharacters(field.get(current).toString());
               writer.writeEndElement();
            }
         }
         writer.writeEndElement();
      }
      writer.writeEndElement();
      writer.flush();
      writer.close();
   }
}
